package cn.tworice.document.visio;

import cn.tworice.document.config.DocumentProperties;
import cn.tworice.document.vo.DownloadRequestVO;
import cn.tworice.document.vo.GenerateResVO;
import cn.tworice.upload.service.UploadUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.annotation.Resource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

@Component
@Slf4j
public class VisioExecutor {

    @Resource
    private UploadUtil uploadUtil;

    @Resource
    private DocumentProperties documentProperties;

    /**
     * 处理Visio文件，将处理后的内容输出到ByteArrayOutputStream
     * @param outputStream ByteArrayOutputStream
     * @param vo 目标文档内容请求
     */
    public void processVisioFile(ByteArrayOutputStream outputStream, DownloadRequestVO vo) {
        try {
            String filePath = this.getDocumentPath(vo.getPath());

            // Step 1: 将 .vsdx 文件读取为字节数组
            byte[] fileBytes = Files.readAllBytes(Paths.get(filePath));

            // Step 2: 使用 Zip 解压文件
            ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
            ZipInputStream zis = new ZipInputStream(bais);

            // Step 3: 创建一个内存中的 Zip 输出流来存储修改后的文件
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ZipOutputStream zos = new ZipOutputStream(baos);

            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {
                // 读取当前 ZipEntry 内容
                ByteArrayOutputStream tempBaos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len;
                while ((len = zis.read(buffer)) > 0) {
                    tempBaos.write(buffer, 0, len);
                }

                byte[] entryData = tempBaos.toByteArray();

                // Step 4: 检查是否是 pages/page1.xml
                if (entry.getName().equals("visio/pages/page1.xml")) {
                    // 解析 XML 并替换字符串
                    for (int i = vo.getVariables().size() - 1; i >= 0; i--) {
                        entryData = replaceStringInXml(entryData, vo.getVariables().get(i).getVariable(), vo.getVariables().get(i).getValue());
                    }
                }

                // 将修改后的或原始的 Entry 写入到 Zip 输出流
                zos.putNextEntry(new ZipEntry(entry.getName()));
                zos.write(entryData);
                zos.closeEntry();
            }

            // 关闭 Zip 输入流和 Zip 输出流
            zis.close();
            zos.close();

            // Step 5: 将 ByteArrayOutputStream 中的数据写入传入的 outputStream
            outputStream.write(baos.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 替换XML文件中的字符串
     * @param xmlData XML文件数据
     * @param targetString 原内容
     * @param replacement 替换内容
     * @return
     * @throws Exception
     */
    private byte[] replaceStringInXml(byte[] xmlData, String targetString, String replacement) throws Exception {
        // 使用 DocumentBuilder 解析 XML
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        ByteArrayInputStream bais = new ByteArrayInputStream(xmlData);
        Document doc = builder.parse(bais);

        // 找到所有文本节点并替换内容
        NodeList nodeList = doc.getElementsByTagName("*");
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                NodeList children = node.getChildNodes();
                for (int j = 0; j < children.getLength(); j++) {
                    Node child = children.item(j);
                    if (child.getNodeType() == Node.TEXT_NODE && child.getNodeValue().contains(targetString)) {
                        child.setNodeValue(child.getNodeValue().replace(targetString, replacement));
                    }
                }
            }
        }

        // 将修改后的 XML 转换为字节数组
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        StreamResult result = new StreamResult(baos);
        transformer.transform(source, result);

        return baos.toByteArray();
    }

    /**
     * 获取文档路径
     * @param filePath 文件名称
     * @return 完整的路径
     */
    private String getDocumentPath(String filePath) {
        return uploadUtil.getUploadPath() + documentProperties.getVisio() + File.separator + filePath;
    }


}
